#!/bin/bash

###############################################################################
# Spring Boot 应用启动脚本（优化版 - 适用于2核2G服务器）
# 项目名称: enterprise-portal
# JAR文件: portal-1.0.0.jar
###############################################################################

# 应用配置
APP_NAME="enterprise-portal"
JAR_NAME="portal-1.0.0.jar"
APP_PORT=8091

# 获取脚本所在目录
cd "$(dirname "$0")" || exit 1
BASE_DIR=$(pwd)
JAR_PATH="$BASE_DIR/target/$JAR_NAME"
LOG_DIR="$BASE_DIR/logs"
PID_FILE="$BASE_DIR/$APP_NAME.pid"

# 创建日志目录
mkdir -p "$LOG_DIR"

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 打印函数
print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 检查Java版本
print_info "检查Java环境..."
if ! command -v java &> /dev/null; then
    print_error "未找到Java命令，请先安装Java"
    exit 1
fi

JAVA_VERSION=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{print $1}')
print_info "检测到Java版本: $JAVA_VERSION"

# 检查JAR文件是否存在
if [ ! -f "$JAR_PATH" ]; then
    print_error "JAR文件不存在: $JAR_PATH"
    print_info "请先执行 mvn clean package 构建项目"
    print_info "或者将JAR文件放在 target 目录下"
    exit 1
fi

# 检查是否已经运行
if [ -f "$PID_FILE" ]; then
    OLD_PID=$(cat "$PID_FILE")
    if ps -p "$OLD_PID" > /dev/null 2>&1; then
        print_warn "应用已在运行中 (PID: $OLD_PID)"
        print_info "如需重启，请先执行 ./stop.sh"
        exit 1
    else
        print_warn "发现过期的PID文件，正在清理..."
        rm -f "$PID_FILE"
    fi
fi

###############################################################################
# JVM参数配置 - 针对2核2G服务器优化
###############################################################################

# 内存配置（2G服务器推荐配置）
# 堆内存：1280MB（预留720MB给系统、元空间、直接内存等）
# 初始堆：640MB（减少启动时的内存调整开销）
JAVA_MEM_OPTS="-Xms640m -Xmx1280m"

# 元空间配置（存储类元数据）
JAVA_MEM_OPTS="$JAVA_MEM_OPTS -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"

# GC配置 - 使用G1垃圾回收器（适合中等内存应用）
JAVA_GC_OPTS="-XX:+UseG1GC"
# G1 GC调优参数
JAVA_GC_OPTS="$JAVA_GC_OPTS -XX:MaxGCPauseMillis=200"           # 最大GC暂停时间200ms
JAVA_GC_OPTS="$JAVA_GC_OPTS -XX:G1HeapRegionSize=4m"           # G1区域大小4MB
JAVA_GC_OPTS="$JAVA_GC_OPTS -XX:InitiatingHeapOccupancyPercent=45"  # 堆占用45%时触发并发GC
JAVA_GC_OPTS="$JAVA_GC_OPTS -XX:G1ReservePercent=10"           # 保留10%内存防止晋升失败
JAVA_GC_OPTS="$JAVA_GC_OPTS -XX:ParallelGCThreads=2"           # 并行GC线程数（2核CPU）
JAVA_GC_OPTS="$JAVA_GC_OPTS -XX:ConcGCThreads=1"               # 并发GC线程数

# GC日志配置（便于问题排查）- 根据Java版本自动选择
if [ "$JAVA_VERSION" -ge 9 ]; then
    # Java 9+ 使用统一日志框架
    JAVA_GC_LOG="-Xlog:gc*:file=$LOG_DIR/gc-%t.log:time,level,tags:filecount=5,filesize=50M"
else
    # Java 8 使用传统GC日志参数
    JAVA_GC_LOG="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:$LOG_DIR/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=50M"
fi

# JVM性能优化参数
JAVA_OPTS="-server"                                             # 服务器模式
JAVA_OPTS="$JAVA_OPTS -XX:+UseStringDeduplication"             # 字符串去重（减少内存占用）
JAVA_OPTS="$JAVA_OPTS -XX:+OptimizeStringConcat"               # 优化字符串拼接
JAVA_OPTS="$JAVA_OPTS -XX:+UseCompressedOops"                  # 压缩对象指针（减少内存占用）
JAVA_OPTS="$JAVA_OPTS -XX:+UseCompressedClassPointers"         # 压缩类指针

# 线程栈大小配置（减少线程内存占用）
JAVA_OPTS="$JAVA_OPTS -Xss256k"                                # 每个线程栈256KB（默认1MB）

# 异常处理
JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError"         # OOM时生成堆转储
JAVA_OPTS="$JAVA_OPTS -XX:HeapDumpPath=$LOG_DIR/heapdump.hprof"  # 堆转储路径
JAVA_OPTS="$JAVA_OPTS -XX:ErrorFile=$LOG_DIR/hs_err_pid%p.log"   # JVM崩溃日志

# 快速启动优化
JAVA_OPTS="$JAVA_OPTS -XX:TieredStopAtLevel=1"                 # 仅使用C1编译器（快速启动）

# -noverify 在Java 13+已废弃，仅在Java 8-12中使用
if [ "$JAVA_VERSION" -lt 13 ]; then
    JAVA_OPTS="$JAVA_OPTS -noverify"                           # 跳过字节码验证（加快启动）
fi

# 网络优化
JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"         # 优先使用IPv4

###############################################################################
# Spring Boot 应用参数
###############################################################################

# 指定配置环境（生产环境请改为prod）
SPRING_OPTS="--spring.profiles.active=prod"

# 指定服务端口
SPRING_OPTS="$SPRING_OPTS --server.port=$APP_PORT"

# 优化Tomcat线程配置（适配2核CPU）
SPRING_OPTS="$SPRING_OPTS --server.tomcat.threads.max=100"            # 最大线程数100（默认200）
SPRING_OPTS="$SPRING_OPTS --server.tomcat.threads.min-spare=20"      # 最小空闲线程20（默认10）
SPRING_OPTS="$SPRING_OPTS --server.tomcat.max-connections=500"       # 最大连接数500（默认8192）
SPRING_OPTS="$SPRING_OPTS --server.tomcat.accept-count=100"          # 等待队列100（默认100）
SPRING_OPTS="$SPRING_OPTS --server.tomcat.connection-timeout=20000"  # 连接超时20秒

# 减少日志输出（生产环境）
SPRING_OPTS="$SPRING_OPTS --logging.level.root=WARN"
SPRING_OPTS="$SPRING_OPTS --logging.level.com.zomiot.portal=INFO"
SPRING_OPTS="$SPRING_OPTS --logging.pattern.console="               # 禁用控制台日志
SPRING_OPTS="$SPRING_OPTS --logging.file.name=$LOG_DIR/application.log"
SPRING_OPTS="$SPRING_OPTS --logging.file.max-size=100MB"
SPRING_OPTS="$SPRING_OPTS --logging.file.max-history=7"

###############################################################################
# 启动应用
###############################################################################

print_info "=================================="
print_info "正在启动应用: $APP_NAME"
print_info "JAR文件: $JAR_NAME"
print_info "端口: $APP_PORT"
print_info "内存配置: 堆内存640m-1280m, 元空间256m"
print_info "GC策略: G1GC"
print_info "日志目录: $LOG_DIR"
print_info "=================================="

# 组合完整的启动命令
nohup java $JAVA_MEM_OPTS $JAVA_GC_OPTS $JAVA_GC_LOG $JAVA_OPTS \
    -jar "$JAR_PATH" $SPRING_OPTS \
    > "$LOG_DIR/startup.log" 2>&1 &

# 保存PID
echo $! > "$PID_FILE"
PID=$(cat "$PID_FILE")

print_info "应用已启动 (PID: $PID)"
print_info "正在检查启动状态..."

# 等待应用启动（最多等待90秒）
COUNT=0
MAX_COUNT=45

while [ $COUNT -lt $MAX_COUNT ]; do
    sleep 2
    COUNT=$((COUNT + 1))

    # 检查进程是否还在运行
    if ! ps -p "$PID" > /dev/null 2>&1; then
        print_error "应用启动失败！进程已退出"
        print_info "请查看日志: tail -f $LOG_DIR/startup.log"
        rm -f "$PID_FILE"
        exit 1
    fi

    # 检查端口是否已监听
    if netstat -tln 2>/dev/null | grep -q ":$APP_PORT " || ss -tln 2>/dev/null | grep -q ":$APP_PORT "; then
        print_info "=================================="
        print_info "应用启动成功！"
        print_info "PID: $PID"
        print_info "端口: $APP_PORT"
        print_info "查看日志: tail -f $LOG_DIR/application.log"
        print_info "查看启动日志: tail -f $LOG_DIR/startup.log"
        print_info "查看GC日志: ls -lh $LOG_DIR/gc-*.log"
        print_info "=================================="
        exit 0
    fi

    # 每10秒显示一次进度
    if [ $((COUNT % 5)) -eq 0 ]; then
        print_info "等待中... ($COUNT/45)"
    fi
done

print_warn "应用可能启动较慢，进程仍在运行中 (PID: $PID)"
print_info "请稍后检查日志: tail -f $LOG_DIR/startup.log"
exit 0
